//Add trim function to Javascript strings
String.prototype.trim = function() 
{
	return this.replace(/^[\s\t\n\r]+|[\s\t\n\r]+$/g, '');
}


/* === GridColumnValidator ============================ */
function GridColumnValidator(regexPattern)
{
    this.RegexPattern = regexPattern;
}
GridColumnValidator.prototype.IsValid = function(value)
{
    return value.match(this.RegexPattern);
}
/* =============================== */



/* === GridColumn ============================ */
function GridColumn(newTitle, newValidator)
{
	this.Title = newTitle;
	this.baseCellElement = null;
	this.Validator = null;
	if(newValidator) this.Validator = newValidator;
}
GridColumn.prototype.Create = function(value)
{
	if(this.baseCellElement == null)
	{
		this.baseCellElement = this.CreateCell();
	}
	var node = this.baseCellElement.cloneNode(true);
	this.SetValue(node, value);
	return node;
};
GridColumn.prototype.CreateCell = function()
{
	var cell = document.createElement('span');
	return cell;
}
GridColumn.prototype.SetValue = function(element, value)
{
	element.appendChild(document.createTextNode(value.trim()));
}
GridColumn.prototype.GetValue = function(element)
{
    return element.childNodes[0].nodeValue;
}
GridColumn.prototype.IsValueValid = function(element)
{
	if( this.Validator)
	{
		return this.Validator.IsValid(this.GetValue(element));
	}

	//Return true if no validator is defined
	return true;
}
/* =============================== */

/* === EditableTextColumn ============================ */
function EditableTextColumn(newTitle, newValidator)
{
	this.Title = newTitle;
	if(newValidator) this.Validator = newValidator;
}
EditableTextColumn.prototype = new GridColumn();
EditableTextColumn.prototype.CreateCell = function()
{
	var cell = document.createElement('textarea');
	cell.className = 'editableCell';
	return cell;
};
EditableTextColumn.prototype.SetValue = function(element, value)
{
	element.value = value.trim();
};
EditableTextColumn.prototype.GetValue = function(element)
{
	return element.value;
};
/* =============================== */

/* === DropDownListColumn ============================ */
function DropDownListColumn(newTitle, optionsArray)
{
	this.Title = newTitle;
	this.OptionsArray = optionsArray;
	this.SelectedItemIndex = 0;
}
DropDownListColumn.prototype = new GridColumn();
DropDownListColumn.prototype.CreateCell = function()
{
	var cell = document.createElement('select');
	for(var i = 0; i < this.OptionsArray.length; i++)
	{
	    cell.options[i] = this.OptionsArray[i];
	    if(this.OptionsArray[i].selected || this.OptionsArray[i].defaultSelected){
	        this.SelectedItemIndex = i;
	    }
	}
	return cell;
};
DropDownListColumn.prototype.SetValue = function(element, targetValue)
{
    var found = false;
	for(var i = 0; i < element.options.length; i++)
	{
		if(element.options[i].value == targetValue)
		{
			element.selectedIndex = i;
			found = true;
			break;
		}
	}
	if(!found){ //Workaround for IE7 "losing" the selected flag
	    element.selectedIndex = this.SelectedItemIndex;
	}
};
DropDownListColumn.prototype.GetValue = function(element)
{
	return element.options[element.selectedIndex].value;
};
/* =============================== */



/* === ImportGrid ============================ */
function ImportGrid(targetElement)
{
	this.TargetElement = targetElement;
	this.BaseRowElementArray = new Array();
}
ImportGrid.prototype.AddColumn = function(column)
{ 
	var index = this.BaseRowElementArray.length;
	this.BaseRowElementArray[index] = column;
	return index;
};
ImportGrid.prototype.RemoveColumn = function(index)
{ 
	this.BaseRowElementArray.splice(index, 1);
};
ImportGrid.prototype.RenderHeader = function()
{
	var thead = document.createElement('thead');
	
	var htmlrow = document.createElement('tr');
	var htmlcell = null;

	htmlcell = document.createElement('th');
	htmlcell.className = 'headerCell';
	htmlcell.appendChild(document.createTextNode(''));
	htmlrow.appendChild(htmlcell);
	
	for(var j = 0; j < this.BaseRowElementArray.length; j++)
	{
		htmlcell = document.createElement('th');
		htmlcell.className = 'headerCell';
		var text = '';
		if(this.BaseRowElementArray[j].Title != null)
		{
			text = this.BaseRowElementArray[j].Title;
		}
		htmlcell.appendChild(document.createTextNode(text));
		htmlrow.appendChild(htmlcell);
	}
	thead.appendChild(htmlrow);
	return thead;
};
ImportGrid.prototype.RenderFooter = function()
{
	var tfoot = document.createElement('tfoot');
	tfoot.style.height='0px';
	return tfoot;
};
ImportGrid.prototype.RenderBody = function(data)
{
	var htmltbody = document.createElement('tbody');
	
	var htmlrow = null;
	var htmlcell = null;
	for(var i = 0; i < data.length; i++)
	{
		htmlrow = document.createElement('tr');
		
		htmlcell = document.createElement('td');
		htmlcell.className = 'countercell';
		htmlcell.appendChild(document.createTextNode(i + 1));
		htmlrow.appendChild(htmlcell);
		
		var j = 0;
		for(j = 0; j < data[i].length && j < this.BaseRowElementArray.length; j++)
		{
			htmlcell = document.createElement('td');
			htmlcell.className = 'cell';
			htmlcell.appendChild(this.BaseRowElementArray[j].Create(data[i][j]));
			htmlrow.appendChild(htmlcell);
		}
		while(j < this.BaseRowElementArray.length)
		{
			htmlcell = document.createElement('td');
			htmlcell.className = 'cell';
			htmlcell.appendChild(this.BaseRowElementArray[j].Create(''));
			htmlrow.appendChild(htmlcell);
			j++;
		}
		htmltbody.appendChild(htmlrow);
	}
	return htmltbody;
};
ImportGrid.prototype.Render = function(data)
{
	this.Clear();
	var target = this.TargetElement;
	
	var htmltable = document.createElement('table');
	htmltable.style.border = '1px solid black';
	
	htmltable.appendChild(this.RenderHeader());
	htmltable.appendChild(this.RenderBody(data));
	htmltable.appendChild(this.RenderFooter());
	
	target.appendChild(htmltable);
};
ImportGrid.prototype.Clear = function()
{
	var target = this.TargetElement;
	if(target.childNodes.length > 0)
	{
		children = target.childNodes;
		for(var i = 0; i < children.length; i++)
		{
			target.removeChild(children[i]);
		}
	}
};
ImportGrid.prototype.GetData = function(table)
{
    //Extract data from the DOM and output a 2D string array
    var result = Array();
	if(table != null && table.tBodies.length > 0)
	{
		var rows = table.tBodies[0].childNodes;
		for(var i = 0; i < rows.length; i++)
		{
			data = new Array();
			cols = rows[i].childNodes;
			rowlength = cols.length;
			for(var j = 0; j < cols.length && j < this.BaseRowElementArray.length; j++)
			{
				var node = cols[j+1].childNodes[0]; //j+1 to skip the row number column
				data[j] = this.BaseRowElementArray[j].GetValue(node).trim().replace(/"/g,'\\"');
			}
			result[i] = data;
		}
	}
	return result;
}
ImportGrid.prototype.Serialize = function()
{
    
	var el = this.TargetElement;
	var resultvalue = '';
	if(el.childNodes.length > 0)
	{
		var rowlength = 0;
		var table = null;
		var children = el.childNodes;
		//Look for table in childNodes
		for(var i = 0; i < children.length; i++)
		{
			if(children[i].nodeName.toLowerCase() == 'table')
			{
				table = children[i];
				break;
			}
		}
	
		//Parse Table
		if(table != null && table.tBodies.length > 0)
		{
		    var data = this.GetData(table);
		    
		    //Convert data to JSON array or arrays
			var innerresult = new Array();
			var row = null;
			for(var i = 0; i < data.length; i++)
			{
				innerresult[i] = '["' + data[i].join('","') + '"]';
			}
			resultvalue = '[' + innerresult.join(',') + ']';
		}
	}
	return resultvalue;
};
/* =============================== */



/*===========================*/
function TabDelimitedDeserialize(data)
{
    //Convert tab delimited string to a 2D string array
	var table = new Array();
	results = data.match(/\t/gi);
	if(results != null && results.length > 1)
	{
		rows = data.split(/\r?\n/gi);
		for(i = 0; i < rows.length; i++)
		{
			if( rows[i].length > 0)
			{
				table[i] = rows[i].split(/\t/gi);
			}
		}
	}
	return table;
}
/*===========================*/
